<template>
	<!-- #ifdef APP-NVUE -->
	<list
		class="e-list"
		:enableBackToTop="props.enableBackToTop"
		:loadmoreoffset="props.lowerThreshold"
		:showScrollbar="props.showScrollbar"
		:renderReverse="props.renderReverse"
		:style="[listStyle]"
		:offset-accuracy="Number(props.offsetAccuracy)"
		@scroll="onScroll"
		@loadmore="scrolltolower"
		@tap="handleClick"
	>
		<slot />
	</list>
	<!-- #endif -->
	<!-- #ifndef APP-NVUE -->
	<scroll-view
		class="e-list"
		:scroll-into-view="props.scrollIntoView"
		:style="[listStyle]"
		scroll-y
		:scroll-top="Number(props.scrollTop)"
		:lower-threshold="Number(props.lowerThreshold)"
		:upper-threshold="Number(props.upperThreshold)"
		:show-scrollbar="props.showScrollbar"
		:enable-back-to-top="props.enableBackToTop"
		:scroll-with-animation="props.scrollWithAnimation"
		@scroll="onScroll"
		@scrolltolower="scrolltolower"
		@scrolltoupper="scrolltoupper"
		@tap="handleClick"
	>
		<view>
			<slot />
		</view>
	</scroll-view>
	<!-- #endif -->
</template>
<script lang="ts">
	import {
		defineComponent
	} from 'vue'
	import mpMixin from "../../libs/mixin/mpMixin";
	/**
	 * List 列表
	 * @description 该组件为高性能列表组件
	 * @tutorial https://www.uviewui.com/components/list.html
	 * @property {Boolean}			showScrollbar		控制是否出现滚动条，仅nvue有效 （默认 false ）
	 * @property {Boolean}			renderReverse		 是否从底部渲染，仅nvue有效
	 * @property {String ｜ Number}	lowerThreshold		距底部多少时触发scrolltolower事件 （默认 50 ）
	 * @property {String ｜ Number}	upperThreshold		距顶部多少时触发scrolltoupper事件，非nvue有效 （默认 0 ）
	 * @property {String ｜ Number}	scrollTop			设置竖向滚动条位置（默认 0 ）
	 * @property {String ｜ Number}	offsetAccuracy		控制 onscroll 事件触发的频率，仅nvue有效（默认 10 ）
	 * @property {Boolean}			enableFlex			启用 flexbox 布局。开启后，当前节点声明了display: flex就会成为flex container，并作用于其孩子节点，仅微信小程序有效（默认 false ）
	 * @property {Boolean}			pagingEnabled		是否按分页模式显示List，（默认 false ）
	 * @property {Boolean}			scrollable			是否允许List滚动（默认 true ）
	 * @property {String}			scrollIntoView		值应为某子元素id（id不能以数字开头）
	 * @property {Boolean}			scrollWithAnimation	在设置滚动条位置时使用动画过渡 （默认 false ）
	 * @property {Boolean}			enableBackToTop		iOS点击顶部状态栏、安卓双击标题栏时，滚动条返回顶部，只对微信小程序有效 （默认 false ）
	 * @property {String ｜ Number}	height				列表的高度 （默认 0 ）
	 * @property {String ｜ Number}	width				列表宽度 （默认 0 ）
	 * @property {String ｜ Number}	preLoadScreen		列表前后预渲染的屏数，1代表一个屏幕的高度，1.5代表1个半屏幕高度  （默认 1 ）
	 * @property {Object}			customStyle			定义需要用到的外部样式
	 *
	 * @example <e-list @scrolltolower="scrolltolower"></e-list>
	 */
	export default defineComponent({
		name: 'e-list',
		mixins: [mpMixin]
	})
</script>
<script lang="ts" setup>
	import {ref,reactive,computed,toRefs,watch,getCurrentInstance,provide} from 'vue'
	import {
		listProps,
		listEmits
	} from './props';
	import {
		deepMerge,
		sys,
		sleep
	} from '../../libs/utils'
	import {
		addUnit,
		addStyle
	} from '../../libs/utils/_utils'
	import type {
		StyleProperties
	} from "../../libs/tokens";
	import {
		useDefaultProps
	} from '../../libs/hooks'
	import componentsProps from "../../libs/config/componentsProps";
	import type {
		 ListProps
	} from "../../libs/config/propsType";
	import  { type ListContext,type ListItemContext,listContextKey } from '../../libs/tokens'
	
	
	
	const {
		list: listDefaultProps
	} = toRefs(componentsProps);
	
	const _props = defineProps(listProps)
	const props = useDefaultProps <ListProps> (_props, listDefaultProps);
	const emit = defineEmits(listEmits)
	
	const ctx = getCurrentInstance()
	
	const _sys = sys()
	
	const children = ref<ListItemContext[]>([])
	
	const addField: ListContext['addField'] = (field) => {
		children.value.push(field)
	}
	
	const removeField: ListContext['removeField'] = (field) => {
		let index = children.value.indexOf(field)
		if (index > -1) {
			children.value.splice(index, 1)
		}
	}
	const getChildIndex: ListContext['getChildIndex'] = (id) => children.value.findIndex(item => item.id === id)
	
	
	
	const innerScrollTop = ref(0)
	const offset = ref(0)
	
	watch(() => props.value.scrollIntoView,(n) => {
		scrollIntoViewById(n)
	})
	
	const listStyle = computed(() => {
		let style:StyleProperties = {}
		if(props.value.width != 0)style.width = addUnit(props.value.width)
		if (props.value.height != 0) style.height = addUnit(props.value.height)
		// 如果没有定义列表高度，则默认使用屏幕高度
		if (!style.height) style.height = addUnit(_sys.windowHeight, 'px')
		return deepMerge(style, addStyle(props.value.customStyle as Record<string,any>) as Record<string,any>)
	})
	
	const updateOffsetFromChild = (top:number) => {
		offset.value = top
	}
	const onScroll = (e:any) => {
		let scrollTop = 0
		// #ifdef APP-NVUE
		scrollTop = e.contentOffset.y
		// #endif
		// #ifndef APP-NVUE
		scrollTop = e.detail.scrollTop
		// #endif
		innerScrollTop.value = scrollTop
		emit('scroll', Math.abs(scrollTop))
	}
	let dom:any
	const scrollIntoViewById = (id?:string) => {
		// #ifdef APP-NVUE
		if(!id) return
		if(!dom){
			dom = uni.requireNativePlugin('dom')
		}
		// 根据id参数，找到所有u-list-item中匹配的节点，再通过dom模块滚动到对应的位置
		const item = children.value.find(item => {
			return item.id === id
		})
		if(item){
			dom.scrollToElement(item.item, {
				// 是否需要滚动动画
				animated: props.value.scrollWithAnimation
			})
		}
		
		// #endif
	}
	
	const handleClick = () => {
		emit('click')
	}
	
	// 滚动到底部触发事件
	const scrolltolower = ()=> {
		sleep(30).then(() => {
			emit('scrolltolower')
		})
	}
	// #ifndef APP-NVUE
	// 滚动到底部时触发，非nvue有效
	const scrolltoupper = () => {
		sleep(30).then(() => {
			emit('scrolltoupper')
			// 这一句很重要，能绝对保证在性功能障碍的webview，滚动条到顶时，取消偏移值，让页面置顶
			offset.value = 0
		})
	}
	// #endif
	
	
	provide(listContextKey, reactive({
		props,
		children,
		innerScrollTop,
		addField,
		removeField,
		getChildIndex,
		updateOffsetFromChild
	}))
</script>

<style lang="scss" scoped>
	@import "../../libs/theme/list.scss";
</style>
